package yaty.lee.tencent.weibo.util;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;

import yaty.lee.tencent.weibo.domain.BackInfo;
import yaty.lee.tencent.weibo.domain.UploadPicBackInfo;
import yaty.lee.tencent.weibo.domain.VO;

import com.alibaba.fastjson.JSON;

public class HttpURLConnectionUtil {
    private static final Logger log = Logger.getLogger(HttpURLConnectionUtil.class.getName());

    public static BackInfo postToObject(VO vo) {
        return JSON.parseObject(post(vo), BackInfo.class);
    }

    public static UploadPicBackInfo upload(VO vo) {
        return JSON.parseObject(post(vo), UploadPicBackInfo.class);
    }

    public static String get(VO vo) {
        try {
            return get(vo.getReqUrl() + "?" + vo.toString());
        } catch (MalformedURLException e) {
            log.info("MalformedURLException: " + vo.getReqUrl());
        } catch (IOException e) {
            log.info("IOException: " + e.getStackTrace());
        }
        return null;
    }

    public static String get(String string) throws IOException {
        StringBuffer backInfo = new StringBuffer();

        URL url = new URL(string);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String line = null;
        while ((line = reader.readLine()) != null) {
            backInfo.append(line);
        }
        reader.close();
        connection.disconnect();

        return backInfo.toString();
    }

    public static String post(VO vo) {
        StringBuffer backInfo = new StringBuffer();

        try {
            URL url = new URL(vo.getReqUrl());
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();

            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestProperty("Content-Length", vo.toString().getBytes(StandardCharsets.UTF_8).length + "");

            OutputStream out = new DataOutputStream(connection.getOutputStream());
            out.write(vo.toString().getBytes(StandardCharsets.UTF_8));
            out.flush();
            out.close();

            BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                backInfo.append(line);
            }
            reader.close();
            connection.disconnect();
        } catch (MalformedURLException e) {
            log.info("MalformedURLException: " + vo.getReqUrl());
        } catch (ProtocolException e) {
            log.info("ProtocolException: " + vo.getReqUrl());
        } catch (UnsupportedEncodingException e) {
            log.info("UnsupportedEncodingException: " + e.getStackTrace());
        } catch (IOException e) {
            log.info("IOException: " + e.getStackTrace());
        }

        log.info("BACKINFO: " + backInfo.toString());
        return backInfo.toString();
    }

    public static BackInfo postFileToObject(VO vo) {
        return JSON.parseObject(postFile(vo), BackInfo.class);
    }

    public static String postFile(VO vo) {
        MultipartUtil multipartUtil = new MultipartUtil();

        HttpURLConnection httpConn = null;
        OutputStream out = null;
        BufferedReader reader = null;
        StringBuffer backInfo = new StringBuffer();

        try {
            Map<String, Object> map = ReflectUtil.getAllField(vo);

            for (Entry<String, Object> entry : map.entrySet()) {
                if ("pic".equalsIgnoreCase(entry.getKey())) {
                    continue;
                }
                multipartUtil.addFormField(entry.getKey(), entry.getValue());
            }
            multipartUtil.addFilePart("pic", map.get("pic").toString());

            URL url = new URL(vo.getReqUrl());
            httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setDoOutput(true);
            httpConn.setDoInput(true);
            httpConn.setUseCaches(false);
            httpConn.setRequestMethod("POST");
            httpConn.setRequestProperty("connection", "Keep-Alive");
            httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Linux; Android 4.3; Nexus 4 Build/JWR66Y) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Mobile Safari/537.36");
            httpConn.setRequestProperty("Accept-Charset", "UTF-8");
            httpConn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + MultipartUtil.BOUNDARY);
            httpConn.setRequestProperty("Content-Length", multipartUtil.getLength() + "");

            out = new DataOutputStream(httpConn.getOutputStream());
            out.write(multipartUtil.getData());
            out.flush();

            reader = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
            String line = null;
            while ((line = reader.readLine()) != null) {
                backInfo.append(line);
            }
        } catch (MalformedURLException e) {
            log.info("MalformedURLException: " + vo.getReqUrl());
        } catch (ProtocolException e) {
            log.info("ProtocolException: " + vo.getReqUrl());
        } catch (UnsupportedEncodingException e) {
            log.info("UnsupportedEncodingException: " + e.getStackTrace());
        } catch (IOException e) {
            log.info("IOException: " + e.getMessage());
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            try {
                if (reader != null) {
                    reader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (httpConn != null) {
                httpConn.disconnect();
            }
        }

        return backInfo.toString();
    }

    public static Map<String, String> urlParamAnalysis(String urlParam) {
        String[] params = urlParam.split("&");
        Map<String, String> map = new HashMap<String, String>();
        String[] split;

        for (String param : params) {
            split = param.split("=");
            log.info("url拼接: " + split[0] + "#" + (split.length > 1 ? split[1] : "空"));
            map.put(split[0], split.length > 1 ? split[1] : "");
        }

        return map;
    }

    public static <T> T urlParamAnalysis(String urlParam, Class<T> clazz) {
        log.info("开始反射, urlParam=" + urlParam + ", clazz" + clazz.getName());
        Map<String, String> map = null;
        T t = null;

        try {
            map = urlParamAnalysis(urlParam);
            t = clazz.newInstance();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (!field.isAccessible()) {
                    field.setAccessible(true);
                }

                String fieldName = field.getName();
                String fieldTypeName = field.getType().getName();
                log.info("反射值: " + fieldName + "#" + fieldTypeName);
                if ("int".equals(fieldTypeName)) {
                    if (map.get(fieldName) != null) {
                        field.setInt(t, Integer.parseInt(map.get(fieldName)));
                    }
                } else if ("long".equals(fieldTypeName)) {
                    if (map.get(fieldName) != null) {
                        field.setLong(t, Long.parseLong(map.get(fieldName)));
                    }
                } else {
                    field.set(t, map.get(fieldName));
                }
            }
        } catch (NumberFormatException e) {
            log.info("NumberFormatException");
        } catch (InstantiationException e) {
            log.info("InstantiationException");
        } catch (IllegalAccessException e) {
            log.info("IllegalAccessException");
        } catch (SecurityException e) {
            log.info("SecurityException");
        } catch (IllegalArgumentException e) {
            log.info("IllegalArgumentException");
        }

        return t;
    }
}
